﻿

using Google.Protobuf.WellKnownTypes;
using MySql.Data.MySqlClient;
using MySqlX.XDevAPI.Common;
using System.Collections.Generic;
using System.ComponentModel.Design;
using static System.Net.Mime.MediaTypeNames;

public partial class UserServer
{
    public static device FindInDeviceTable(string uuid)
    {
        if (string.IsNullOrEmpty(uuid))
        {
            GameDebug.LogError($"FindInDeviceTable  uuid empty");
            return null;
        }

        return MysqlFunction.FindInTable<device>(ServerConfig.DBShared,SqlTable.device, "uuid", uuid);

    }


    public static users FindInUserTable(long deviceId)
    {
        string database = users.GetUserDatabaseWithDeviceId(deviceId);
        long userTableId = users.DeviceId2UserTableId(deviceId);

        GameDebug.Log($"userId:{deviceId}  所在数据库是：{database}  userTableId:{userTableId}");
            
        return MysqlFunction.FindInTable<users>(database, SqlTable.users, "id", userTableId.ToString());
    }
    //public static users FindInUserTableWithNick(string nick)
    //{
    //    return FindInTable<users>(SqlTable.users, "nickname", nick);

    public static skins[] FindInSkinsTable(long userId)
    {
        return MysqlFunction.FindRowsInTable<skins>(users.GetUserDatabaseWithDeviceId(userId), SqlTable.skins,"uid", userId.ToString());
    }

    public static UserTable[] FindInUsersTable(int gender, string userLocationCity, string userHometownProvince,
        string userHometownCity, Requirement requirement,int num)
    {
        UserTable[] usersFetch = new UserTable[num];

        int index = 0;

        for (int i = 1; i <= 10; i++)
        {
            var getusers = FindUsersRowsInTable<users>(users.GetUserDatabaseWithDbId(i), SqlTable.users,  gender, 
                userLocationCity, userHometownProvince, userHometownCity, requirement, num);

            for(int j = 0; j < getusers.Length; j++)
            {
                usersFetch[index] = new UserTable(i,getusers[j]);

                index++;

                if(index >= num)
                {
                    return usersFetch;
                }
            }
        }

        return usersFetch;
    }
    public static T[] FindUsersRowsInTable<T>(string database, SqlTable table, int gender, string userLocationCity,
        string userHometownProvince, string userHometownCity, Requirement requirement,
         int maxCount = int.MaxValue) where T : class, new()
    {
        T[] res = new T[0];
        SelectUsersFromTable(database, table.ToString(), gender, userLocationCity,
            userHometownProvince, userHometownCity, requirement, 
        (reader) =>
        {
            if (reader.HasRows)
            {
                T[] tables = null;
                MysqlFunction.ReadTable(reader, ref tables, table.ToString(), maxCount);
#if SomeLog
                GameDebug.Log($"table.ToString():{tables.GetArrStr()}");
#endif
                res = tables;
            }
        });
#if SomeLog
        GameDebug.Log($"FindRowsInTable:{res.GetArrStr()}");
#endif
        return res;
    }
    public static void SelectUsersFromTable(string database, string table, int gender,
        string userLocationCity, string userHometownProvince, string userHometownCity, Requirement requirement,
        Action<MySqlDataReader> onEnd)
    {
        int curYear = DateTime.Now.Year;
        int maxBirthYear = curYear - requirement.minAge;
        int minBirthYear = curYear - requirement.maxAge;

        string sqlInPark = $"select * from {table} where gender = '{gender}' and birthYear >= '{minBirthYear}' and birthYear <= '{maxBirthYear}'";
        sqlInPark += $" and height >= '{requirement.minHeight}' and height <= '{requirement.maxHeight}'";
        sqlInPark += $" and education >= '{requirement.minEdu}'";

        if(requirement.sameLocation && !string.IsNullOrEmpty(userLocationCity))
            sqlInPark += $" and location_city = '{userLocationCity}'";
        if (requirement.sameHometown)
        {
            if (string.IsNullOrEmpty(userHometownProvince))
            {
                if(!string.IsNullOrEmpty(userHometownCity))
                    sqlInPark += $" and hometown_city = '{userHometownCity}'";
            }
            else 
            {
                sqlInPark += $" and hometown_province = '{userHometownProvince}'";
            }
        }
        if (requirement.onlyUnmarried)
            sqlInPark += $" and marital_status = '{MaritalStatus.unmarried}'";

        //string sqlInPark = string.Format(@"select * from {0} where {1} = '{2}' and {3} = '{4}' and {5} = '{6}'", table, column1, target1, column2, target2, column3, target3);
#if SomeLog
        GameDebug.Log("curYear:"+curYear+"  SelectFromTable sql:" + sqlInPark);
#endif
        MysqlHelper.ExecuteReader(database, sqlInPark, onEnd);
    }

    public static User UserTable2User(long deviceId,users userTable)
    {
        //texture[] textureTable = UserServer.FindInTextureTable(existDevice.id);
        var icon = TextureSaver.GetUserTextureUrl(deviceId, 1);
        var tex1 = TextureSaver.GetUserTextureUrl(deviceId, 2);
        var tex2 = TextureSaver.GetUserTextureUrl(deviceId, 3);
        var tex3 = TextureSaver.GetUserTextureUrl(deviceId, 4);
        var tex4 = TextureSaver.GetUserTextureUrl(deviceId, 5);
        var tex5 = TextureSaver.GetUserTextureUrl(deviceId, 6);
        var tex6 = TextureSaver.GetUserTextureUrl(deviceId, 7);

        return ReadUserTable(deviceId, userTable, icon, tex1, tex2, tex3, tex4, tex5, tex6);
    }

    public static User ReadUserTable(string database, users ut, string icon,
      string tex1, string tex2, string tex3, string tex4, string tex5, string tex6)
    {
        long deviceId = users.UserTableId2DeviceId(database, ut.id);
        return ReadUserTable(deviceId, ut, icon, tex1, tex2, tex3, tex4, tex5, tex6);
    }

    public static User ReadUserTable(long deviceId, users ut, string icon,
      string tex1, string tex2, string tex3, string tex4, string tex5, string tex6)
    {
        UserInfo userInfo = UserTable2UserInfo(deviceId, ut, icon, tex1, tex2, tex3, tex4, tex5, tex6);

        User user = new User(deviceId, ut.nickname, "", ut.max_lv, ut.coin, ut.diamond, ut.is_robot > 0, ut.login_day,
            users.ObtainedLoginBonusString2List(ut.obtain_login_bonus_day), users.String2LongList(ut.friends), userInfo);//, petIds, usedSkinIndexes, powers, propertyProportions);

        user.UpdateRequire(ut.requirement_min_age, ut.requirement_max_age, ut.requirement_min_height, ut.requirement_max_height,
            ut.requirement_min_edu, ut.requirement_same_location, ut.requirement_same_hometown, ut.requirement_only_unmarried);

        user.likes = users.String2LongList(ut.likes);
        user.belikes = users.String2LongList(ut.belikes);
        user.myFollows = users.String2LongList(ut.myfollows);
        user.followers = users.String2LongList(ut.followers);

        //GameDebug.Log($"Requirement minAge:{user.requirement?.minAge}");

        applys[] requestApplysArr = UserServer.FindInApplysTableWithSourceUserID(deviceId);
        applys[] receivesApplysArr = UserServer.FindInApplysTableWithTargetUserID(deviceId);

        chats[] requestChatsArr = UserServer.FindInChatsTableWithSourceUserID(deviceId);
        chats[] receiveChatsArr = UserServer.FindInChatsTableWithTargetUserID(deviceId);

        visits[] requestvisitsArr = UserServer.FindInVisitsTableWithSourceUserID(deviceId);
        visits[] receivevisitsArr = UserServer.FindInVisitsTableWithTargetUserID(deviceId);

        user.applies = new List<Apply>();
        user.applies.AddRange(requestApplysArr.Map(e=> ApplyTable2Apply(e)).AsList());
        user.applies.AddRange(receivesApplysArr.Map(e => ApplyTable2Apply(e)).AsList());

        user.chats = new List<Chat>();
        user.chats.AddRange(requestChatsArr.Map(e => ChatTable2Chat(e)).ToList());
        user.chats.AddRange(receiveChatsArr.Map(e => ChatTable2Chat(e)).ToList());

        //user获取个人动态数据。登录先不发
        moments[] momentsArr = UserServer.FindInMomentsTableWithUserID(deviceId);

        List<Moment> moments = new List<Moment>(momentsArr.Length);
        for (int i = 0; i < momentsArr.Length; i++)
        {
            moments.Add(NetHandler_FetchMoments.Table2Moment(momentsArr[i]));
        }
        user.moments = moments;

        user.myVisits = requestvisitsArr.Map(e => VisitTable2MyVisit(e.target_user_id, e.last_visit_time,e.total_visit_count,
           GetUserInfoWithUserId(e.target_user_id,true))).ToList();
        user.visitors = receivevisitsArr.Map(e => VisitTable2MyVisit(e.uid, e.last_visit_time, e.total_visit_count,
           GetUserInfoWithUserId(e.uid,true))).ToList();

        user.obtainShareReward = ut.obtain_shared_reward;

        //GameDebug.Log($"tex1:{userInfo.tex1 != null}");
        return user;
    }

    public static UserInfo GetUserInfoWithUserId(long deviceId,bool onlyIcon = false)
    {
        users ut = UserServer.FindInUserTable(deviceId);

        UserInfo userInfo = null;
        if (ut == null)
            return userInfo;

        var icon = TextureSaver.GetUserTextureUrl(deviceId, 1);
        if (!onlyIcon)
        {
            var tex1 = TextureSaver.GetUserTextureUrl(deviceId, 2);
            var tex2 = TextureSaver.GetUserTextureUrl(deviceId, 3);
            var tex3 = TextureSaver.GetUserTextureUrl(deviceId, 4);
            var tex4 = TextureSaver.GetUserTextureUrl(deviceId, 5);
            var tex5 = TextureSaver.GetUserTextureUrl(deviceId, 6);
            var tex6 = TextureSaver.GetUserTextureUrl(deviceId, 7);
            userInfo = UserServer.UserTable2UserInfo(deviceId, ut, icon, tex1, tex2, tex3, tex4, tex5, tex6);
        }
        else
        {
            userInfo = UserServer.UserTable2UserInfo(deviceId, ut, icon, null, null, null, null, null, null);
        }

        return userInfo;
    }

    public static UserInfo UserTable2UserInfo(long deviceId, users ut, string icon,
      string tex1, string tex2, string tex3, string tex4, string tex5, string tex6)
    {
        UserInfo userInfo = new UserInfo(deviceId, ut.gender, ut.name, ut.birthYear, ut.birthMonth, ut.birthDay, ut.status,
            ut.location_province,ut.location_city,ut.hometown_province, ut.hometown_city, ut.job, ut.company, ut.education,
            ut.school, ut.height, ut.weight, ut.income, ut.realNameVerify, ut.jobVerify, ut.eduVerify, 
            ut.aboutMe, ut.familyBackground, ut.interest, ut.loveView, ut.idealCompanion,
        users.String2LongList(ut.followers).ToArray(), icon, tex1, tex2, tex3, tex4, tex5, tex6);

        return userInfo;
    }
    public static Apply ApplyTable2Apply(applys table)
    {
        Apply apply = new Apply(table.uid, table.target_user_id, table.result, table.msg, table.reject_msg, table.apply_time, table.view_time, table.result_time);
        return apply;
    }

    public static Chat ChatTable2Chat(chats table)
    {
        Chat chat = new Chat();
        chat.userId1 = table.from_user_id;
        chat.userId2 = table.target_user_id;
        chat.dialogues = Newtonsoft.Json.JsonConvert.DeserializeObject<Dialogue[]>(CommonFunctions.DecompressJson(table.content));
        return chat;
    }
    public static Visit VisitTable2MyVisit(long userId,long lastVisitTime,int totalVisitCount, UserInfo user)
    {
        Visit visit = new Visit();
        visit.userId = user.userId;
        visit.gender = user.gender;
        visit.name = user.name;
        visit.birthYear = user.birthYear;
        visit.locationCity = user.locationCity;
        visit.height = (int)user.height;
        visit.iconTex = user.icon;
        visit.lastVisitTime = lastVisitTime;
        visit.totalVisitCount = totalVisitCount;
        return visit;
    }

    public static applys[] FindInApplysTableWithSourceUserID(long userId)
    {
        return MysqlFunction.FindRowsInTable<applys>(users.GetUserDatabaseWithDeviceId(userId), SqlTable.applys, "uid", userId.ToString());
    }
    public static applys[] FindInApplysTableWithTargetUserID(long target_user_id)
    {
        List<applys> tables = new List<applys>();

        for(int dbId =1; dbId <= 10; dbId++)
        {
            applys[] applysArr = MysqlFunction.FindRowsInTable<applys>(users.GetUserDatabaseWithDbId(dbId), SqlTable.applys, "target_user_id", target_user_id.ToString());
            tables.AddRange(applysArr);
        }
        return tables.ToArray();
    }

    public static chats[] FindInChatsTableWithSourceUserID(long userId)
    {
        return MysqlFunction.FindRowsInTable<chats>(users.GetUserDatabaseWithDeviceId(userId), SqlTable.chats, "from_user_id", userId.ToString());
    }
    public static chats[] FindInChatsTableWithTargetUserID(long target_user_id)
    {
        List<chats> tables = new List<chats>();

        for (int dbId = 1; dbId <= 10; dbId++)
        {
            var chatsArr = MysqlFunction.FindRowsInTable<chats>(users.GetUserDatabaseWithDbId(dbId), SqlTable.chats, "target_user_id", target_user_id.ToString());
            tables.AddRange(chatsArr);
        }
        return tables.ToArray();
    }
    public static visits[] FindInVisitsTableWithSourceUserID(long userId)
    {
        return MysqlFunction.FindRowsInTable<visits>(users.GetUserDatabaseWithDeviceId(userId), SqlTable.visits, "uid", userId.ToString(),100);
    }
    public static visits[] FindInVisitsTableWithTargetUserID(long target_user_id)
    {
        List<visits> tables = new List<visits>();

        for (int dbId = 1; dbId <= 10; dbId++)
        {
            var chatsArr = MysqlFunction.FindRowsInTable<visits>(users.GetUserDatabaseWithDbId(dbId), SqlTable.visits, "target_user_id", target_user_id.ToString());
            tables.AddRange(chatsArr);
        }
        return tables.ToArray();
    }
    public static visits FindInVisitTable(long fromId,long toId)
    {
        string database = users.GetUserDatabaseWithDeviceId(fromId);
        long userTableId = users.DeviceId2UserTableId(fromId);

        //GameDebug.Log($"userId:{fromId}  所在数据库是：{database}  userTableId:{userTableId}");
        return MysqlFunction.FindInTable<visits>(database, SqlTable.visits,"uid", fromId.ToString(), "target_user_id", toId.ToString());
    }

    public static moments[] FindInMomentsTableWithUserID(long user_id)
    {
        string database = users.GetUserDatabaseWithDeviceId(user_id);

        var arr = MysqlFunction.FindRowsInTable<moments>(database, SqlTable.moments, "uid", user_id.ToString());

        return arr;
    }
    public static moments[] SelectMomentsTableDesc(int num)
    {
        List<moments> tables = new List<moments>();
        for (int dbId = 1; dbId <= 10; dbId++)
        {
            var arr = MysqlFunction.SelectRowsInTableDesc<moments>(users.GetUserDatabaseWithDbId(dbId), SqlTable.moments,num);

            foreach(var table in arr)
            {
                tables.Add(table);

                if (tables.Count >= num)
                {
                    return tables.ToArray();
                }
            }
        }
        return tables.ToArray();
    }
    public static moments[] SelectMomentsTableDesc(string locationCity, int num)
    {
        return SelectMomentsTableDesc("user_location_city", locationCity, num);
    }
    public static moments[] SelectMomentsTableDesc(string col,string value,int num)
    {
        List<moments> tables = new List<moments>();
        for (int dbId = 1; dbId <= 10; dbId++)
        {
            var arr = MysqlFunction.SelectRowsInTableDesc<moments>(users.GetUserDatabaseWithDbId(dbId), SqlTable.moments, col, value, num);

            foreach (var table in arr)
            {
                tables.Add(table);

                if (tables.Count >= num)
                {
                    return tables.ToArray();
                }
            }
        }
        return tables.ToArray();
    }

    public static comments FindInCommentTable(long momentUserId,long commentId)
    {
        string database = users.GetUserDatabaseWithDeviceId(momentUserId);
        return MysqlFunction.FindInTable<comments>(database, SqlTable.comments, "id", commentId.ToString());

    }
    public static moments FindInMomentTable(long momentUserId, long momentId)
    {
        string database = users.GetUserDatabaseWithDeviceId(momentUserId);
        return MysqlFunction.FindInTable<moments>(database, SqlTable.moments, "id", momentId.ToString());
    }
}